package cn.ac.registAService.service.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;

import cn.ac.registAService.commons.util.CswTool;
import cn.ac.registAService.commons.util.Pair;
import cn.ac.registAService.commons.util.Pair.Three;
import cn.ac.registAService.commons.util.XmlReader;
import cn.ac.registAService.exception.BusinessException;
import cn.ac.registAService.model.MetadataIso;
import cn.ac.registAService.service.IMetadataManager;

/**
 * @author yangzhong E-mail: zyang@ceode.ac.cn
 * @version 1.0
 * @date 2012-10-17 下午1:15:09
 * @fuction IMetadataManager实现类
 */

public class MetadataManagerImpl implements IMetadataManager {

	//元数据模版根元素
	Element metadataRootElement=null;
	
	static Logger logger=Logger.getLogger(MetadataManagerImpl.class.getName());

	@Override
	public boolean insert(MetadataIso metadataIso) throws BusinessException {
		//console argument
		if(metadataIso==null)
			throw new BusinessException("传入参数为null,"+MetadataManagerImpl.class.getName());
		
         //判断资源插入是否成功
		boolean b=false;
		
		//设置UUId的值
		metadataIso.setFileIdentifier(UUID.randomUUID().toString());
		
		//1、获取元数据模版根元素	
		logger.info("6.1添加资源：获取元数据模版根元素");		
		if(metadataRootElement==null)
		{
			try {
				Document metadataDocument=XmlReader.getDocument(CswTool.metadataXmlPath);
				metadataRootElement=metadataDocument.getRootElement();
			} catch (DocumentException e) {
				throw new BusinessException("读取元数据模版出错，文件路径"+CswTool.metadataXmlPath);
			}			
		}
		
		//2、获取插入资源模版Insert元素
		logger.info("6.2添加资源：获取插入资源模版");
		Document insertDocument=null;
			try {
				// 插入资源元数据
				insertDocument=XmlReader.getDocument(CswTool.insertXmlPath);
			} catch (DocumentException e) {
				throw new BusinessException("读取插入资源模版出错，文件路径"+CswTool.insertXmlPath);
			}
		
		Element insertElement=insertDocument.getRootElement().element("Insert");
			
		//3、设置资源值
		logger.info("6.3添加资源：设置资源值");
		try {
			metadataRootElement=CswTool.setMetadata(metadataRootElement, metadataIso);
		} catch (BusinessException e) {
			throw new BusinessException("设置资源值出错");
		}
					
		//4在资源模版中加入元数据元素
		logger.info("6.4在资源模版中加入元数据元素");
		insertElement.add(metadataRootElement);

		//5、添加资源
		String requestXml = insertDocument.asXML();
		logger.info("6.5添加资源requestXml:"+"\n"+requestXml);
		String responseXml = CswTool.loginAndRun(requestXml);
		logger.info("6.5添加资源requestXml:"+"\n"+responseXml);
		
		//6拿到修改结果值
		logger.info("6.6查询资源：从返回结果中看是否插入成功");
			if(totalNumber(responseXml, "totalInserted")>=1)
			{
				b=true;
			}

	
//      //---test----------------------------------------------------------------------------
//		//6 生成成request临时文件
//		logger.info("6.6添加资源：开始生成临时文件");
//		String requestFilePath = CswTool.cswTempletePath + File.separator + "insertRequestTemp.xml";
//		try {
//			FileTool.writeFileContent(requestXml, requestFilePath);
//		} catch (IOException e) {
//			//System.err.println(("资源插入请求文件保存失败："+ MetadataManager.class.getName()+",文件路径"+requestFilePath));
//			logger.warn("资源插入请求文件保存失败:文件路径"+requestFilePath);
//			e.printStackTrace();
//		}
//		
//		// 生成response临时文件
//		String responseFilePath = CswTool.cswTempletePath + File.separator
//				+ "insertResponseTemp.xml";
//		try {
//			FileTool.writeFileContent(responseXml, responseFilePath);
//		} catch (IOException e) {
//			//System.err.println(("资源插入返回结果文件保存失败："+ MetadataManager.class.getName()+",文件路径"+responseFilePath));
//			logger.warn("资源插入返回结果文件保存失败:文件路径"+responseFilePath);
//			e.printStackTrace();
//		}
//		logger.info("6.6添加资源：生成临时文件成功");

		return b;
	}


	@Override
	public boolean update(MetadataIso metadataIso) throws BusinessException
	{			
		//修改结果
		boolean b=false;
		
		//1、获取元数据模版根元素	
		logger.info("6.1修改资源：获取元数据模版根元素");		
		if(metadataRootElement==null)
		{
			try {
				Document metadataDocument=XmlReader.getDocument(CswTool.metadataXmlPath);
				metadataRootElement=metadataDocument.getRootElement();
			} catch (DocumentException e) {
				throw new BusinessException("读取元数据模版出错，文件路径"+CswTool.metadataXmlPath);
			}			
		}
		
		//2、获取修改资源模版
		logger.info("6.2修改资源：获取修改资源模版");
		Document updateDocument=null;
			try {
				// 插入资源元数据
				updateDocument=XmlReader.getDocument(CswTool.updateFilePath);
			} catch (DocumentException e) {
				throw new BusinessException("读取插入资源模版出错，文件路径"+CswTool.insertXmlPath);
			}
		
		//3设置要修改资源的条件
		logger.info("6.3修改资源：设置资源UUID值");
		String updateXmlPath="/csw:Transaction/csw:Update/csw:Constraint/ogc:Filter/ogc:PropertyIsEqualTo/ogc:Literal";
		Element idElement=(Element)updateDocument.selectSingleNode(updateXmlPath);
		System.out.println("idElement:"+idElement.getName());
		idElement.setText(metadataIso.getFileIdentifier());
			
		//3设置资源值
		logger.info("6.3修改资源：设置资源值");
		Element updateElement=updateDocument.getRootElement().element("Update");
		try {
			metadataRootElement=CswTool.setMetadata(metadataRootElement, metadataIso);
		} catch (BusinessException e) {
			throw new BusinessException("设置资源值出错");
		}
					
		//4在资源模版中加入元数据元素
		logger.info("6.4修改资源：在资源模版中加入元数据元素");
		updateElement.add(metadataRootElement);
					
		//5修改资源
		String requestXml = updateDocument.asXML();
		logger.info("6.5修改资源requestXml:"+"\n"+requestXml);
		String responseXml = CswTool.loginAndRun(requestXml);
		logger.info("6.5修改资源requestXml:"+"\n"+responseXml);
		
		//6拿到修改结果值
		logger.info("6.6查询资源：从返回结果中看是否修改成功");
			if(totalNumber(responseXml, "totalUpdated")>=1)
			{
				b=true;
			}
			
//		//--------------test
//		//6 生成成request临时文件
//		logger.info("6.6添加资源：开始生成临时文件");
//		String requestFilePath = CswTool.cswTempletePath + File.separator + "updateRequestTemp.xml";
//		try {
//			FileTool.writeFileContent(requestXml, requestFilePath);
//		} catch (IOException e) {
//			//System.err.println(("资源插入请求文件保存失败："+ MetadataManager.class.getName()+",文件路径"+requestFilePath));
//			logger.warn("资源插入请求文件保存失败:文件路径"+requestFilePath);
//			e.printStackTrace();
//		}
//		
//		// 生成response临时文件
//		String responseFilePath = CswTool.cswTempletePath + File.separator
//				+ "updateResponseTemp.xml";
//		try {
//			FileTool.writeFileContent(responseXml, responseFilePath);
//		} catch (IOException e) {
//			//System.err.println(("资源插入返回结果文件保存失败："+ MetadataManager.class.getName()+",文件路径"+responseFilePath));
//			logger.warn("资源插入返回结果文件保存失败:文件路径"+responseFilePath);
//			e.printStackTrace();
//		}
//		logger.info("6.6添加资源：生成临时文件成功");
		
	
		return b;
		
	}

	@Override
	public boolean delete(String id) throws BusinessException {
		
		//删除结果
		boolean b=false;
		
		//删除资源xml
		Document deleteDocument = null;
		
        //1请求xml
		logger.info("4.1删除资源：获取删除资源模版");
			try {
				deleteDocument=XmlReader.getDocument(CswTool.deleteFilePath);
			} catch (DocumentException e) {
				throw new BusinessException("读取删除资源模版出错，文件路径"+CswTool.deleteFilePath);
			}
			
		//2设置资源值
		logger.info("4.2删除资源：设置资源UUID值");
		String deleteXmlPath="/csw:Transaction/csw:Delete/csw:Constraint/ogc:Filter/ogc:PropertyIsEqualTo/ogc:Literal";
		Element idElement=(Element)deleteDocument.selectSingleNode(deleteXmlPath);
		
		idElement.setText(id);
					
		//3删除资源
		String requestXml = deleteDocument.asXML();
		logger.info("4.3删除资源requestXml:"+"\n"+requestXml);
		String responseXml = CswTool.loginAndRun(requestXml);
		logger.info("4.3删除资源responseXml:"+"\n"+responseXml);
		
		//4拿到删除结果值
//		logger.info("4.4查询资源：从返回结果中看是否删除成功");
//		try {
//			Element deleteResultRootElement=XmlReader.StringToXml(responseXml).getRootElement();
//			
//			if(deleteResultRootElement.getName().equals("TransactionResponse"))
//			{
//				Element totalDeletedElement=deleteResultRootElement.element("TransactionSummary").element("totalDeleted");
//				int totalDeleted=Integer.valueOf(totalDeletedElement.getTextTrim());
//				if(totalDeleted>=1)
//				{
//			        b=true;
//				}
//			}
//			
//		} catch (DocumentException e) {
//			throw new BusinessException("从返回结果中无法拿到删除数量值");
//		}
		
		//4拿到修改结果值
		logger.info("4.4删除资源：从返回结果中看是否删除成功");
			if(totalNumber(responseXml, "totalDeleted")>=1)
			{
				b=true;
			}
	
		return b;
	}

	@Override
	public MetadataIso getRecordById(String id) throws BusinessException {		
		
		//查询结果
		MetadataIso metadataIso=null;
		
		//查询资源模版
		Document queryDocument = null;
		
		//1获取查询资源模版Id元素
		logger.info("5.1查询资源：获取查询资源模版");
			try {
				queryDocument=XmlReader.getDocument(CswTool.queryByIdFilePath);
			} catch (DocumentException e) {
				throw new BusinessException("读取查询资源模版出错，文件路径"+CswTool.queryByIdFilePath);
			}
			
		//2设置资源值
		logger.info("5.2查询资源：设置资源UUID值");
		Element idElement=queryDocument.getRootElement().element("Id");
		idElement.setText(id);
					
		//3查询资源
		String requestXml = queryDocument.asXML();
		logger.info("4.3查询资源requestXml:"+"\n"+requestXml);
		String responseXml = CswTool.loginAndRun(requestXml);
		logger.info("4.3查询资源responseXml:"+"\n"+responseXml);
			
		//4从查询结果中取值
		logger.info("5.4查询资源：从查询结果中取值");
		try {
				List<Element> metadataList=XmlReader.StringToXml(responseXml).selectNodes("/csw:GetRecordByIdResponse/gmd:MD_Metadata");
				if(metadataList.size()>0)
				{
					metadataRootElement=metadataList.get(0);
			        metadataIso=CswTool.getMetadata(metadataRootElement);
				}		
		} catch (DocumentException e) {
			throw new BusinessException("从查询结果中无法拿到资源信息，可能是没有符合查询条件的资源："+e.getMessage());
		}


//      //---TEST---------------------------------------------------------------------------------------------	
//		//5生成成request临时文件
//		logger.info("5.5查询资源：开始生成临时文件");
//		String requestFilePath = CswTool.cswTempletePath + File.separator + "queryByIdRequestTemp.xml";
//		try {
//			FileTool.writeFileContent(requestXml, requestFilePath);
//		} catch (IOException e) {
//			logger.warn("资源查询请求文件保存失败:文件路径"+requestFilePath);
//			e.printStackTrace();
//		}
//		
//		//生成response临时文件
//		String responseFilePath = CswTool.cswTempletePath + File.separator
//				+ "queryByIdResponseTemp.xml";
//		try {
//			FileTool.writeFileContent(responseXml, responseFilePath);
//		} catch (IOException e) {
//			logger.warn("资源查询返回结果文件保存失败:文件路径"+responseFilePath);
//			e.printStackTrace();
//		}
//		logger.info("5.5查询资源：生成临时文件成功");

		return metadataIso;
		
	}

	@Override
	public List<MetadataIso> getRecords() throws BusinessException {
		return getRecords(null,0,1).getRight();
	}
	
	@Override
	public Pair<String, List<MetadataIso>> getRecords(String strQuery, long maxRecords,long startPosition) throws BusinessException {
		Three<String, Map<String, String>, List<MetadataIso>> threeTuple=getRecordsAllInfor(strQuery, maxRecords,startPosition);
		String matchedRecords=threeTuple.getLeft();
		List<MetadataIso> listMetadata=threeTuple.getC();
				
		return Pair.of(matchedRecords, listMetadata);
	}
	
	@Override
	public Map<String,String> getOrganization() throws BusinessException 
	{
		Three<String, Map<String, String>, List<MetadataIso>> threeTuple=getRecordsAllInfor(null, 1,1);
		Map<String, String> orgMap=threeTuple.getRight();
		
		return orgMap;		
	}
    
    @Override
 	public Three<String, Map<String, String>, List<MetadataIso>> getRecordsAllInfor(String strQuery,long maxRecords,long startPosition) throws BusinessException
 	{
 		String matchedRecords=null;  //符合查询条件的资源数目
 		//TODO 存放summary中的信息（目前只存资源组织信息<资源组织名称，资源组织数目>，后期可扩展存储服务等信息）
 		Map<String, String> hashMap=new HashMap<String,String>();  
 		List<MetadataIso> arrayList=new ArrayList<MetadataIso>(); //存放返回的资源信息
 		
 		Pair<Element, Element> pair=getRecordsResponse(strQuery, maxRecords,startPosition);
 		
 		Element summaryElement=pair.getLeft();
 		Element searchResultsElement=pair.getRight();
 		logger.info("GetRecords的summary节点"+"\n"+summaryElement.asXML());
 		logger.info("GetRecords的searchResultsElement节点"+"\n"+searchResultsElement.asXML());
 		
 		try {
 			if(summaryElement!=null)
 			{
 				List<Element> listOrg=summaryElement.selectNodes("//organizationNames/organizationName");
 				if(listOrg!=null)
 				{
 					for(Element el:listOrg)
 					{
 						String orgName=el.attributeValue("name");   //资源组织名称
 						String orgCount=el.attributeValue("count"); //资源组织数目
 						hashMap.put(orgName, orgCount);
 					} //end for(Element el:listOrg)
 				} //end if(listOrg!=null)	
 			} //end if(summaryElement!=null)
 			
 			if(searchResultsElement!=null)
 			{
 				matchedRecords=searchResultsElement.attributeValue("numberOfRecordsMatched");

 				List<Element> listMetadata=searchResultsElement.selectNodes("//gmd:MD_Metadata");
 								
 				if(listMetadata!=null)
 				{
 					for(Element el:listMetadata)
 					{
 						arrayList.add(CswTool.getMetadata(el));
 					}
 				} //end if(listMetadata!=null)
 				
 			}  //end if(searchResultsElement!=null)
 						
 			return Pair.Three.of(matchedRecords, hashMap, arrayList);
 		} 				
 		catch (BusinessException e) {
 			throw new BusinessException("GetRecords处理返回结果出错："+e.getMessage());
 		}
 		
 	}
	
//	/**
//	 * GetTecords操作，查询符合条件的资源
//	 * @param strQuery 查询条件
//	 * @param maxRecords  	return Pair.of(, right);
//	 * @return Pair<Element, Element>
//	 * 第一个Element记录返回结果中节点geonet:Summary 的信息，第二个Element记录返回结果中节点csw:SearchResults信息
//	 * @throws BusinessException
//	 */
//	private Pair<Element, Element> getRecordsResponse(String strQuery,long maxRecords) throws BusinessException
//	{
//			//查询资源模版
//			Document queryDocument = null;
//			
//			//1获取查询资源模版
//			logger.info("4.1查询多个资源：获取查询资源模版");
//				try {
//					queryDocument=XmlReader.getDocument(CswTool.getRecordsFilePath);
//				} catch (DocumentException e) {
//					throw new BusinessException("读取查询多个资源模版出错，文件路径"+CswTool.getRecordsFilePath);
//				}
//			
//            //设置返回结果数目(如果为0，返回全部结果)
//				if(maxRecords>0)
//				{
//					queryDocument.getRootElement().addAttribute("maxRecords", Long.toString(maxRecords));
//				}
//				
//		    //2设置查询条件
//				logger.info("4.2查询多个资源：设置查询条件");
//				Element queryElement=(Element)queryDocument.selectSingleNode("/csw:GetRecords/csw:Query/csw:Constraint/ogc:Filter");
//				if(strQuery!=null && strQuery!="")
//				queryElement.setText(strQuery);
//				
//			//3查询资源
//			String requestXml = queryDocument.asXML();
//			logger.info("4.3查询多个资源requestXml:"+"\n"+requestXml);
//			String responseXml = CswTool.loginAndRun(requestXml);
//			logger.info("4.4查询资源responseXml:"+"\n"+responseXml);
//			
//			//4 解析查询结果
//			Document responseDoc;
//			try {
//				responseDoc = XmlReader.StringToXml(responseXml);
//				Element summaryElement=(Element) responseDoc.selectSingleNode("/csw:GetRecordsResponse/geonet:Summary");
//				Element searchResultsElement=(Element) responseDoc.selectSingleNode("/csw:GetRecordsResponse/csw:SearchResults");
//				
//				return Pair.of(summaryElement, searchResultsElement);
//			} catch (DocumentException e) {
//				throw new BusinessException("解析查询结果xml出错："+e.getMessage());
//			}			
//	}

	/**
	 * GetTecords操作，查询符合条件的资源
	 * @param strQuery 查询条件
	 * @param maxRecords  	return Pair.of(, right);
	 * @param startPosition 开始获取数据的位置（从1开始），利用这个位置可以实现分页功能
	 * @return Pair<Element, Element>
	 * 第一个Element记录返回结果中节点geonet:Summary 的信息，第二个Element记录返回结果中节点csw:SearchResults信息
	 * @throws BusinessException
	 */
	private Pair<Element, Element> getRecordsResponse(String strQuery,long maxRecords,long startPosition) throws BusinessException
	{
			//查询资源模版
			Document queryDocument = null;
			
			//1获取查询资源模版
			logger.info("4.1查询多个资源：获取查询资源模版");
				try {
					queryDocument=XmlReader.getDocument(CswTool.getRecordsFilePath);
				} catch (DocumentException e) {
					throw new BusinessException("读取查询多个资源模版出错，文件路径"+CswTool.getRecordsFilePath);
				}
			
            //设置返回结果数目(如果为0，返回全部结果)
				if(maxRecords>0)
					queryDocument.getRootElement().addAttribute("maxRecords", Long.toString(maxRecords));
		    
		   //设置获取数据位置
				if(startPosition>0)
					queryDocument.getRootElement().addAttribute("startPosition", Long.toString(startPosition));
				
		    //2设置查询条件
				logger.info("4.2查询多个资源：设置查询条件");
				Element queryElement=(Element)queryDocument.selectSingleNode("/csw:GetRecords/csw:Query/csw:Constraint/ogc:Filter");
				if(strQuery!=null && !strQuery.equals(""))
				queryElement.setText(strQuery); 
				
			//3查询资源
			//String requestXml = queryDocument.asXML();
			String requestXml = XmlReader.formatXml(queryDocument, false); //查询条件中有转义字符，需要格式化，不转义查询条件中的字符
			logger.info("4.3查询多个资源requestXml:"+"\n"+requestXml);
			String responseXml = CswTool.loginAndRun(requestXml);
			logger.info("4.4查询资源responseXml:"+"\n"+responseXml);
			
			//4 解析查询结果
			Document responseDoc;
			try {
				responseDoc = XmlReader.StringToXml(responseXml);
				Element summaryElement=(Element) responseDoc.selectSingleNode("/csw:GetRecordsResponse/geonet:Summary");
				Element searchResultsElement=(Element) responseDoc.selectSingleNode("/csw:GetRecordsResponse/csw:SearchResults");
				
				return Pair.of(summaryElement, searchResultsElement);
			} catch (DocumentException e) {
				throw new BusinessException("解析查询结果xml出错："+e.getMessage());
			}			
	}
	
	/**
	 * 从TransactionResponse得到Transaction（totalInserted/totalUpdated/totalDeleted）的值
	 * @param responseXml
	 * @param transactionType  在（totalInserted/totalUpdated/totalDeleted）中选择，对应相应操作成功数目
	 * @return  操作成功数目
	 * @throws BusinessException
	 */
	private static int totalNumber(String responseXml,String transactionType) throws BusinessException
	{
          int nubmer=0;

          try {
  			Element updateResultRootElement=XmlReader.StringToXml(responseXml).getRootElement();
  			List<Element>  totalList=XmlReader.StringToXml(responseXml).selectNodes("/csw:TransactionResponse/csw:TransactionSummary/csw:"+transactionType);
			
  			if(totalList.size()>0)
  			{
  				Element totalElement=totalList.get(0);
  				nubmer=Integer.valueOf(totalElement.getTextTrim());
  				
  			}
		} catch (DocumentException e) {
			throw new BusinessException("从返回结果中无法拿到值:"+transactionType);
		}

		return nubmer;
	}
	
}
